package ae.pcfc.cldos.online.common.facade.provider;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.transaction.annotation.Transactional;

import ae.pcfc.cldos.online.common.ConstantsCommon;
import ae.pcfc.cldos.online.common.ConstantsCommon.Steps;
import ae.pcfc.cldos.online.common.UltimusConstants;
import ae.pcfc.cldos.online.common.UltimusConstants.ApplicationResubmitDecision;
import ae.pcfc.cldos.online.common.UltimusConstants.EmployeeType;
import ae.pcfc.cldos.online.common.clddb.domain.AppMetaData;
import ae.pcfc.cldos.online.common.clddb.domain.ApplicationStatus;
import ae.pcfc.cldos.online.common.clddb.domain.NocLetter;
import ae.pcfc.cldos.online.common.clddb.domain.Process;
import ae.pcfc.cldos.online.common.clddb.domain.ReviewComments;
import ae.pcfc.cldos.online.common.clddb.domain.ServiceMaster;
import ae.pcfc.cldos.online.common.clddb.domain.TaskMaster;
import ae.pcfc.cldos.online.common.clddb.domain.TempFileStorage;
import ae.pcfc.cldos.online.common.clddb.domain.manager.NocLetterDOM;
import ae.pcfc.cldos.online.common.etksdb.domain.User;
import ae.pcfc.cldos.online.common.exception.BadAppException;
import ae.pcfc.cldos.online.common.exception.InvalidEmpIdException;
import ae.pcfc.cldos.online.common.exception.UltimusAppException;
import ae.pcfc.cldos.online.common.facade.BaseProcesesFacade;
import ae.pcfc.cldos.online.common.facade.NocLetterFacade;
import ae.pcfc.cldos.online.common.factories.AppMetaDataFactory;
import ae.pcfc.cldos.online.common.manager.BuisnessValidationManager;
import ae.pcfc.cldos.online.common.manager.GSEmployeeDetailsManager;
import ae.pcfc.cldos.online.common.vo.AppSaveResponseVO;
import ae.pcfc.cldos.online.common.vo.UserVO;
import ae.pcfc.cldos.online.common.vo.fnp.FNPPaymentAdviceVO;
import ae.pcfc.cldos.online.common.vo.nandl.NocLetterDetailsVO;
import ae.pcfc.cldos.online.common.vo.nandl.NocLetterVO;
import ae.pcfc.cldos.online.gs.ConstantsGS;
import ae.pcfc.cldos.online.gs.service.client.vo.NotificationVO;
import ae.pcfc.cldos.online.net.service.vo.NOCDetailsFromGSVO;
import ae.pcfc.cldos.online.wf.ConstantsWF;
import ae.pcfc.cldos.online.wf.service.client.vo.appdata.NocLetterAppInfoVO;
import ae.pcfc.cldos.online.wf.service.client.vo.base.BaseResubmitGVariablesVO;
import ae.pcfc.cldos.online.wf.service.client.vo.base.BaseSubmitGVariablesVO;
import ae.pcfc.cldos.online.wf.service.client.vo.base.CompleteStepVO;
import ae.pcfc.cldos.online.wf.service.client.vo.base.LaunchIncedentVO;

/**
 * 
 * @author arosa
 *
 */
public class NocLetterFacadeImpl extends BaseProcesesFacade implements NocLetterFacade{

	private NocLetterDOM nocLetterDOM;
	
	private GSEmployeeDetailsManager gsEmployeeDetailsManager;
	
	private BuisnessValidationManager buisnessValidationManager;
	
	public BuisnessValidationManager getBuisnessValidationManager() {
		return buisnessValidationManager;
	}

	public void setBuisnessValidationManager(
			BuisnessValidationManager buisnessValidationManager) {
		this.buisnessValidationManager = buisnessValidationManager;
	}

	public GSEmployeeDetailsManager getGsEmployeeDetailsManager() {
		return gsEmployeeDetailsManager;
	}

	public void setGsEmployeeDetailsManager(
			GSEmployeeDetailsManager gsEmployeeDetailsManager) {
		this.gsEmployeeDetailsManager = gsEmployeeDetailsManager;
	}

	public void setNocLetterDOM(NocLetterDOM nocLetterDOM) {
		this.nocLetterDOM = nocLetterDOM;
	}
	
	@Transactional
	public NocLetterVO getNocLetterAppInfo(String appId, UserVO userVO, Steps step) throws BadAppException{
		
		NocLetterVO nocLetterVO = new NocLetterVO();
		AppMetaData appMetaData = null;
		
		if(userVO.isGeneralAdmin()){
			appMetaData = appMetaDataDOM
				.getAppMetaDataByIdForGeneralAdmin(appId, Process.PROCESS_NOC_LETTERS, step);
		} else {
			User user = userDomainObjectManager.findUserByUserName(userVO.getUsername());
			appMetaData = appMetaDataDOM
					.getAppMetaDataById(appId, Process.PROCESS_NOC_LETTERS, step, user.getClientId());
		}
		NocLetterDetailsVO nocLetterDetailsVO = 
				new NocLetterDetailsVO();
		getMapper().map(appMetaData.getNocLetter(), nocLetterDetailsVO);
		
		nocLetterVO.setClientReferenceNo(appMetaData.getClientRefNo());
		nocLetterVO.setInitiatedBy(appMetaData.getWfInitiatedBy());
		
		nocLetterVO.setNocLetterDetailsVO(nocLetterDetailsVO);
		nocLetterVO.setApplicationCommentVOs(getCommentsVOList(appMetaData.getReviewComments()));
		
		try{
			nocLetterVO.setWfStatus(gsInfoManager.getWfStatus(nocLetterVO.getClientReferenceNo()));
		}catch(Exception e){
			nocLetterVO.setWfStatus(ConstantsGS.EMP_STATUS_NA);
		}
		return nocLetterVO;
	}
	
	@Transactional(rollbackFor=Exception.class)
	public AppSaveResponseVO submit(NocLetterVO nocLetterVO) throws Exception{
		return storeToDb(nocLetterVO, null, false);
	}
	
	@Transactional(rollbackFor=Exception.class)
	public AppSaveResponseVO reSubmit(NocLetterVO nocLetterVO, String appId) throws Exception{
		return storeToDb(nocLetterVO, appId, true);
	}
	
	private AppSaveResponseVO storeToDb(NocLetterVO nocLetterVO, String appId, boolean isResubmit) throws Exception{
		AppSaveResponseVO appSaveResponseVO = new AppSaveResponseVO();
		Integer incident = null; 
		
		UserVO userVO =  nocLetterVO.getUserVO();
		User user = userDomainObjectManager.findUserAndClientByUserName(userVO.getUsername());
				
		String compLicNo = tTscClientCompanyDOM.getLicenseNumberNyTrakheesId(user.getClient().getCTrakheesId());
		if(userVO.isAdmin()){
			buisnessValidationManager.validateOnlineNOCLettersData(compLicNo);
			if(!gsEmployeeDetailsManager.validateEmployee(nocLetterVO.getNocLetterDetailsVO().getNlEmployeeId(), 
					compLicNo)){
				throw new InvalidEmpIdException();
			}
		}
		AppMetaDataFactory appMetaDataFactory = null;
		String clientRefNo = null;
		boolean backOfficeRejectflag=false;
		if(isResubmit){
			AppMetaData appMetaData = appMetaDataDOM.getAppMetaDataById(appId, 
					Process.PROCESS_NOC_LETTERS, Steps.RESUBMIT, user.getClientId());
			appMetaDataFactory = AppMetaDataFactory.createReSubmitFactory(appMetaData);
			if(appMetaData.getStatusCode()==5){
				backOfficeRejectflag=true;
			}
			if(userVO.isAdmin() && !backOfficeRejectflag){
				clientRefNo = gsInfoManager.getNextOfflineAppId(Process.PROCESS_NOC_LETTERS);
				appMetaData.setClientRefNo(clientRefNo);
			}
		} else {
			if(userVO.isAdmin()){
			 clientRefNo = gsInfoManager.getNextOfflineAppId(Process.PROCESS_NOC_LETTERS);
			}
			appMetaDataFactory = AppMetaDataFactory.createSubmitFactory(clientRefNo);
		}
		
		AppMetaData appMetaData = appMetaDataFactory.getAppMetaData();
		
		Long serviceCode =  ServiceMaster.NOC_LETTER;
		appMetaData.setServiceCode(serviceCode);
		
		if(userVO.isAdmin()){
			appMetaData.setStatusCode(ApplicationStatus.STATUS_APPROVED_BY_ONLINE_ADMIN);
		}else if (!isResubmit) {
			appMetaData.setStatusCode(ApplicationStatus.STATUS_INITIATED);
		} else {
			appMetaData.setStatusCode(ApplicationStatus.STATUS_RESUBMITED);
		}
		
		appMetaData.setProcessCode(Process.PROCESS_NOC_LETTERS);
		appMetaData.setUserId(user.getUId());
		appMetaData.setClientId(user.getClientId());
		
		if(nocLetterVO.getApplicationCommentVO() != null) {
			appMetaData.setApplicationDate(nocLetterVO.getApplicationCommentVO().getDate());
		} else {
			appMetaData.setApplicationDate(new Date());
		}
		
		if(!isResubmit || appMetaData.getApplicationId()==null){
			appMetaDataDOM.add(appMetaData);
		}

		if(isResubmit){
			taskAndNotificationsManager.completeAllByAppId(appMetaData.getApplicationId());
		}
		
		if(!userVO.isAdmin()){	
			taskAndNotificationsManager.sendTask(appMetaData, TaskMaster.__ADMIN_APPROVE_TASK_CODE);
		}
		
		NocLetter nocLetter = appMetaDataFactory.getNocLetter();
		getMapper().map(nocLetterVO.getNocLetterDetailsVO(), nocLetter);
		nocLetter.setAppMetaData(appMetaData);
		nocLetterDOM.add(nocLetter);
		appMetaData.setNocLetter(nocLetter);
		appMetaData.setTempFileStorages(new ArrayList<TempFileStorage>(1));
		
		String referenceNumber = appMetaData.getApplicationId().toString();
		if(!userVO.isAdmin() && !backOfficeRejectflag){
			appMetaData.setClientRefNo(referenceNumber);
		}
		
		//add list of param here
		if(userVO.isAdmin()){
			 String fnpServiceCode = nocLetterVO.getFnpServiceCode();
			 FNPPaymentAdviceVO fnpPaymentAdviceVO = 
					 fnpManager.generatePayment(appMetaData.getApplicationId(), userVO.getUsername(), fnpServiceCode, 
							 nocLetterVO.getFnpParams(),null,appMetaData.getClientRefNo());
			 appMetaData.setPaymentAdviceNo(fnpPaymentAdviceVO.getPaymentAdviceNumber());
			 appMetaData.getTempFileStorages().add(fnpPaymentAdviceVO.getStoredPaymentAdvice());
		}
		NocLetterAppInfoVO nocLetterAppInfoVO = new NocLetterAppInfoVO();
		getMapper().map(nocLetterVO.getNocLetterDetailsVO(), nocLetterAppInfoVO);
		
		//call nst ws to get the missing NOC details
		NOCDetailsFromGSVO nocDetailsFromGSVO = gsEmployeeDetailsManager.getNOCDetailsById(nocLetterVO.getNocLetterDetailsVO().getNlEmployeeId(), compLicNo,referenceNumber);
		getMapper().map(nocDetailsFromGSVO, nocLetterAppInfoVO);
		nocLetterAppInfoVO.setG_NOCLetterInitiated("TRUE");
		nocLetterAppInfoVO.setG_PaymentApproved("TRUE");
		nocLetterAppInfoVO.setG_IfLetterSelected(buisnessValidationManager.getNOCLetterCode(nocLetter.getNlNocLetterType(), nocLetter.getNlTextFormat()));
		
		//launch workflow
		if(appMetaData.getWfIncidentId() == null){
			if(userVO.isAdmin()){
				LaunchIncedentVO launchIncedentVO = new LaunchIncedentVO();
				BaseSubmitGVariablesVO baseSubmitGVariablesVO = new BaseSubmitGVariablesVO();
				baseSubmitGVariablesVO.setG_ApplicationID(referenceNumber);
				baseSubmitGVariablesVO.setG_ApplicationSubmissionMedium(ConstantsCommon.APPLICATION_SUBMISSION_MEDIUM_ONLINE);
				baseSubmitGVariablesVO.setG_ApplicationLaunchedBy(EmployeeType.COMPANY_ADMIN.getEmployeeType());
				try{		
					incident = genericVisaWF.launchIncident(appMetaData.getProcessCode(), launchIncedentVO, baseSubmitGVariablesVO, 
							nocLetterAppInfoVO);
				}catch (Exception e) {
					e.printStackTrace();
					fnpManager.cancelPayment(appMetaData.getApplicationId().toString(), userVO.getUsername(), appMetaData.getPaymentAdviceNo(),appMetaData.getClientRefNo());
					throw new UltimusAppException(e);
				}
				appMetaData.setWfIncidentId(incident.toString());
				appMetaData.setWfInitiatedBy(user.getUUsername());
			}
		} else{
			 incident = Integer.parseInt(appMetaData.getWfIncidentId());
			
			//:TODO put code for WF inwocation for resubmit
			BaseResubmitGVariablesVO baseResubmitGVariablesVO = new BaseResubmitGVariablesVO();
			baseResubmitGVariablesVO.setG_ApplicationID(referenceNumber);
			
			if(!userVO.isAdmin()){
				baseResubmitGVariablesVO.setG_ApplicationResubmittedBy(EmployeeType.EMPLOYEE.getEmployeeType());
			}else{
				baseResubmitGVariablesVO.setG_ApplicationResubmittedBy(EmployeeType.COMPANY_ADMIN.getEmployeeType());
			}
			
			baseResubmitGVariablesVO.setG_ApplicationResubmitDecision(ApplicationResubmitDecision.RESUBMITTED.getResubmitDecision());
			
			CompleteStepVO completeStepVO = new CompleteStepVO();
			completeStepVO.setStrStepName(UltimusConstants.RESUBMIT_ONLINE_APPLICATION_STEP);
			completeStepVO.setStrUserName(ConstantsWF.ULTIMUS_ANONYMOUS_USER);
			completeStepVO.setnIncidentNumber(incident);
			
			try{		
				genericVisaWF.completeStep(appMetaData.getProcessCode(), completeStepVO, baseResubmitGVariablesVO, 
						nocLetterAppInfoVO);
			}catch (Exception e) {
				e.printStackTrace();
				if(userVO.isAdmin()){
					fnpManager.cancelPayment(appMetaData.getApplicationId().toString(), userVO.getUsername(), appMetaData.getPaymentAdviceNo(),appMetaData.getClientRefNo());
				}
				throw new Exception(e);
			}
			
		}
		if(isResubmit){
			appMetaDataDOM.update(appMetaData);
		} else {
			appMetaDataDOM.updateAndAddEtks(appMetaData);
		}
		
		/*
		 * transfer request to GS
		 */
			transferDataToGS(appMetaData, userVO, compLicNo);
		/*
		 * end of transfer
		 */
		
		if(nocLetterVO.getApplicationCommentVO() != null) {
			/*add action comment*/
			ReviewComments reviewComments = new ReviewComments();
			reviewComments.setApplicationId(appMetaData.getApplicationId());
			reviewComments.setStatusCode(appMetaData.getStatusCode());
			reviewComments.setRcUserName(user.getUUsername());
			reviewComments.setRcComments(nocLetterVO.getApplicationCommentVO().getComment());
			reviewCommentsDOM.add(reviewComments);
		} 
		
		NotificationVO notificationVO = new NotificationVO();
		notificationVO.setOnlineAppId(appMetaData.getApplicationId().toString());
		Map<Object, Object> parameters = new HashMap<Object, Object>();
		parameters.put("comments", nocLetterVO.getApplicationCommentVO().getComment());
		notificationVO.setParameters(parameters);
		taskAndNotificationsManager.sendNotification(appMetaData, notificationVO);
		
		appSaveResponseVO.setReferenceNo(appMetaData.getClientRefNo());
		appSaveResponseVO.setIncidentNo(appMetaData.getWfIncidentId());
		return appSaveResponseVO;
	}
	
}
